﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using AnimEditor.Define;
using System.Drawing;
using System.ComponentModel;
using System.IO;

namespace AnimEditor.Physics
{
  public enum EPhysicsShapeType
  {
    EPST_NONE=0,
    EPST_POLYGON=1,
    EPST_CIRCLE=2,
    EPST_BOX=3,
  }

  public class TilePhysics
  {
    PhysicsShape m_Shape = null;
    [Browsable(false)]
    public PhysicsShape Shape
    {
      get { return m_Shape; }
      set { m_Shape = value; }
    }
    float density = 0.0f;
    [Category("物理属性"), Description("密度")]
    public float Density
    {
      get { return density; }
      set { density = value; }
    }
    float friction = 0.0f;
    [Category("物理属性"), Description("摩擦力")]
    public float Friction
    {
      get { return friction; }
      set { friction = value; }
    }
    float restitution = 0.0f;
    [Category("物理属性"), Description("回复力")]
    public float Restitution
    {
      get { return restitution; }
      set { restitution = value; }
    }
    public void Write(BinaryWriter writer)
    {
      writer.Write(density);
      writer.Write(friction);
      writer.Write(restitution);
      if (Shape == null)
        writer.Write(0);
      else
      {
        writer.Write((byte)Shape.Type());
        Shape.Write(writer);
      }
    }
    public bool Read(BinaryReader reader)
    {
      density = reader.ReadSingle();
      friction = reader.ReadSingle();
      restitution = reader.ReadSingle();
      EPhysicsShapeType shapeid = (EPhysicsShapeType)reader.ReadByte();
      bool ret = true;
      switch (shapeid)
      {
        case EPhysicsShapeType.EPST_NONE:
          {
            Shape = null;
          }  
          break;
        case EPhysicsShapeType.EPST_POLYGON:
          {
            Shape = new PolygonShape();
            ret = Shape.Read(reader);
          }
          break;
        case EPhysicsShapeType.EPST_CIRCLE:
          {
            Shape = new CircleShape();
            ret = Shape.Read(reader);
          }
          break;
        case EPhysicsShapeType.EPST_BOX:
          {
            Shape = new BoxShape();
            ret = Shape.Read(reader);
          }
          break;
      }
      return ret;
    }
    public void Clear()
    {
      if (Shape != null)
        Shape.Clear();
      Shape = null;
      density = 0;
      friction = 0;
      restitution = 0;
    }
  }

  public class PhysicsShape : object
  {
    int m_DragPointIndex = -1;

    public int DragPointIndex
    {
      get { return m_DragPointIndex; }
      set { m_DragPointIndex = value; }
    }
    virtual public EPhysicsShapeType Type()
    {
      return EPhysicsShapeType.EPST_NONE;
    }
    virtual public bool Write(BinaryWriter writer) { return true; }
    virtual public bool Read(BinaryReader reader) { return true; }
    virtual public void Clear() { m_DragPointIndex = -1; }
  }

  public class PolygonShape : PhysicsShape
  {
    List<AnimPoint> m_Vertexs = new List<AnimPoint>();
    public List<AnimPoint> Vertexs
    {
      get { return m_Vertexs; }
      set { m_Vertexs = value; }
    }

    public Point[] ToPoints()
    {
      if(m_Vertexs.Count == 0)
        return null;
      Point[] points = new Point[m_Vertexs.Count];
      for(int i=0; i<m_Vertexs.Count; i++)
      {
        points[i] = new Point(m_Vertexs[i].X, m_Vertexs[i].Y);
      }
      return points;
    }

    override public void Clear()
    {
      base.Clear();
      m_Vertexs = new List<AnimPoint>();
    }

    override public EPhysicsShapeType Type()
    {
      return EPhysicsShapeType.EPST_POLYGON;
    }
    override public bool Write(BinaryWriter writer) 
    {
      writer.Write(m_Vertexs.Count);
      foreach (AnimPoint point in m_Vertexs)
      {
        writer.Write(point.X);
        writer.Write(point.Y);
      }
      return true; 
    }
    override public bool Read(BinaryReader reader) 
    {
      int count = reader.ReadInt32();
      for (int i = 0; i < count; i++ )
      {
        int x = reader.ReadInt32();
        int y = reader.ReadInt32();
        m_Vertexs.Add(new AnimPoint(x, y));
      }
      return true;
    }
  }

  public class CircleShape : PhysicsShape
  {
    public CircleShape()
    {
      Clear();
    }

    public Rectangle Rect
    {
      get { return new Rectangle((int)(Center.X-R),(int)(Center.Y-R),(int)(2*R),(int)(2*R)); }
      set 
      {
        m_R = value.Width / 2;
        m_Center.X = (int)(value.X + m_R);
        m_Center.Y = (int)(value.Y + m_R);
      }
    }

    Point m_Center;
    public Point Center
    {
      get { return m_Center; }
      set { m_Center = value; }
    }

    float m_R = 0;
    public float R
    {
      get { return m_R; }
      set { m_R = value; }
    }

    override public void Clear()
    {
      base.Clear();
      m_Center.X = 0;
      m_Center.Y = 0;
      m_R = 0;
    }
    override public EPhysicsShapeType Type()
    {
      return EPhysicsShapeType.EPST_CIRCLE;
    }
    override public bool Write(BinaryWriter writer)
    {
      writer.Write(Center.X);
      writer.Write(Center.Y);
      writer.Write(R);
      return true;
    }
    override public bool Read(BinaryReader reader)
    {
      m_Center.X = reader.ReadInt32();
      m_Center.Y = reader.ReadInt32();
      m_R = reader.ReadSingle();
      return true;
    }
  }

  public class BoxShape : PhysicsShape
  {
    public BoxShape()
    {
    }

    AnimRect m_Rect = null;
    public AnimRect Rect
    {
      get { return m_Rect; }
      set { m_Rect = value; }
    }
    override public void Clear()
    {
      base.Clear();
      m_Rect = null;
    }
    override public EPhysicsShapeType Type()
    {
      return EPhysicsShapeType.EPST_BOX;
    }
    override public bool Write(BinaryWriter writer)
    {
      if (Rect != null)
      {
        writer.Write(Rect.Point.X);
        writer.Write(Rect.Point.Y);
        writer.Write(Rect.Size.Width);
        writer.Write(Rect.Size.Height);
      }
      else
      {
        writer.Write((int)0);
        writer.Write((int)0);
        writer.Write((int)0);
        writer.Write((int)0);
      }
      return true;
    }
    override public bool Read(BinaryReader reader)
    {
      int x = reader.ReadInt32();
      int y = reader.ReadInt32();
      int width = reader.ReadInt32();
      int height = reader.ReadInt32();
      Rect = new AnimRect(x, y, width, height);
      return true;
    }
  }
    
}
